今天要來收尾了,類別這個主題講了8天了,我們即將以 sealed class
, value class
, enum class
收尾,沒有意外會主力著重在 sealed class
,這種類型的類別將影響後面在 Kotlin 上撰寫 Functional Programming 的設計。話不多說,我們開始吧!
密封是什麼?跟我們生活中遇到的密封很像,他在封起來後就與外界隔絕了。這時候你會很好奇,哪個類別不是 code 寫完就定型了,為什麼需要這個呢?那我們從介紹它開始一層層揭開面紗。
從下面範例我們可以看出 sealed class
跟一般 class
相當不同:
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("成功:${result.data}")
is Result.Error -> println("錯誤:${result.message}")
Result.Loading -> println("載入中...")
}
}
上面範例可以看出 sealed class
本身是用來規範哪一些類別或是物件可以屬於這個 sealed class
,所以當我們制定一個端口 (API) 給外部服務來使用並指定一個 sealed class
作為回傳型別就會間接限定使用這個端口的工程師必須使用我制定下的這些類別。
另外,如果大家有注意到 handleResult
裡面的 when
判斷式 (控制流程) 就可以發現他不需要另外給一個 else
敘述做為預設值,這是因為當我們調用 Result
類別的物件作為判斷條件,它就只會有固定的選擇,這種觀念是 Functional Programming 裡面會提到的 “exhaustive” (窮舉/列舉)。 在狀態或情境可以事前知道有限的情況下使用這種寫法可以最大化避免使用 else
需要考慮到的各種錯誤情境,簡化處理錯誤或是預設值的成
當然除了類別之外我們也可以把這項設計套用在介面 (interface
) 上,道理同放在類別上可以限制介面的種類可以讓實作以及調用。
相似於昨天介紹的 data class
,他們都是用來協助儲存資料用的類別,但不同於 data class
的是:
val
。data class
所擁有的內建擴中函式, equals()
、hashCode()
、toString()
和 copy()
。data class
能儲存多筆資料不同,value class
只能儲存一個。讓我們直接看一個範例:
@JvmInline
value class Name(val value: String)
fun main() {
// 創建一個 Name
val name1 = Name("Alice")
println(name1) // 輸出: Name(name=Alice)
val name2 = Name("Alice")
println(name1 == name2) // 輸出: true
// println(name1 === name2) // 輸出: Identity equality for arguments of types Person and Person is forbidden
// name1.value = "John" // 輸出: Val cannot be reassigned
val name = name1.value
println("姓名:$name") // 輸出: 姓名:Alice
}
範例中我們可以特別注意下面被註解的兩行, value class
並不提供我們對物件相同直接做檢查,因為本生就只能用 val
定義,所以所有的物件都是不同也不可修改的。熟悉 Kotlin 的讀者這時候會說:這跟 type aliases
有什麼不一樣嗎?結論是它的慨念確實相似,但在型別安全檢查上有些許差異,礙於篇幅我這邊直接送上官方說明,有興趣的讀者可以去啃一下XD Value class v.s. Type aliases (Kotlin Official)
跟大多數程式語言的 enum
相同,Kotlin 裡的 enum class
是一個用來定義常數名稱集合的類別。這些常數在 enum class
中被列舉出來,並且可以像類別一樣被使用。這種結構提升易讀性與維護性。
以下是一個簡單的Kotlin enum class
範例:
// 定義一個名為Color的enum class
enum class Color { RED, GREEN, BLUE, YELLOW, ORANGE }
fun main() {
// 使用enum class的常數
val selectedColor: Color = Color.RED
// 檢查選擇的顏色並執行相應的動作
when (selectedColor) {
Color.RED -> println("選擇了紅色")
Color.GREEN -> println("選擇了綠色")
Color.BLUE -> println("選擇了藍色")
Color.YELLOW -> println("選擇了黃色")
Color.ORANGE -> println("選擇了橙色")
}
}
在這個例子中,我們定義了一個 Color
的 enum class
,其中包含了幾種不同的顏色。然後透過建立了一個 selectedColor
變數,並使用when
判斷式來窮舉出所有的顏色並印出相應的訊息。enum class
常被用於表示固定集合的常數。